import puppeteer, { Browser, Page } from 'puppeteer'
import { EventEmitter } from 'events'

const PORT = 3001
// 抖音直播信息接口
export interface DyLiveInfo {
  roomNum?: string;
  roomId: string;
  uniqueId: string;
  avatar: string;
  cover: string;
  nickname: string;
  title: string;
  status: number;
}

// 页面事件数据类型定义
interface BasePageEvent {
  type: string
  roomId: string
  timestamp: number
}

interface ConnectionOpenedEvent extends BasePageEvent {
  type: 'connection_opened'
}

interface MessagesEvent extends BasePageEvent {
  type: 'messages'
  messages: Array<{
    user: string
    content: string
    timestamp: number
  }>
}

interface ConnectionClosedEvent extends BasePageEvent {
  type: 'connection_closed'
  reason?: string
}

interface ConnectionErrorEvent extends BasePageEvent {
  type: 'connection_error'
  error: string
}

interface ReconnectingEvent extends BasePageEvent {
  type: 'reconnecting'
  count: number
}

interface ConnectionFailedEvent extends BasePageEvent {
  type: 'connection_failed'
  error: string
}

interface LiveInfoSuccessEvent extends BasePageEvent {
  type: 'live_info_success'
  liveInfo: DyLiveInfo
}

interface LiveInfoFailedEvent extends BasePageEvent {
  type: 'live_info_failed'
  error: string
}

type PageEvent =
  | ConnectionOpenedEvent
  | MessagesEvent
  | ConnectionClosedEvent
  | ConnectionErrorEvent
  | ReconnectingEvent
  | ConnectionFailedEvent
  | LiveInfoSuccessEvent
  | LiveInfoFailedEvent

// 扩展Window接口，添加Puppeteer暴露的函数和页面方法
declare global {
  interface Window {
    // Puppeteer暴露的函数
    __puppeteerReceive: (data: PageEvent) => void
    __puppeteerLog: (level: string, ...args: any[]) => void

    // 页面暴露的方法
    getLiveInfo: (roomId: string) => Promise<DyLiveInfo>
    connectLiveRoom: (roomId: string) => Promise<{ success: boolean; message: string }>
  }
}




// Puppeteer实例管理 - 双Browser架构
export class PuppeteerManager extends EventEmitter {
  // 【主Browser】持久化运行，专门用于WebSocket弹幕连接
  private streamingBrowser: Browser | null = null
  private streamingPage: Page | null = null
  private isStreamingInitialized = false
  private streamingInitPromise: Promise<void> | null = null

  // 【临时Browser】跟踪正在运行的查询Browser，用于清理
  private activeQueryBrowsers = new Set<Browser>()
  private queryBrowserTimestamps = new Map<Browser, number>() // 记录Browser创建时间

  // 【Browser复用】当前查询Browser池
  private currentQueryBrowser: Browser | null = null
  private currentQueryPage: Page | null = null
  private queryBrowserUseCount = 0 // 当前Browser使用次数
  private readonly MAX_QUERY_USE_COUNT = parseInt(process.env.max_query_browser_reuse_count || '10', 10) // Browser最大复用次数

  // 启动配置缓存
  private launchConfig: any = null

  // Browser监控
  private monitorTimer: NodeJS.Timeout | null = null
  private readonly MONITOR_INTERVAL = 60000 // 每分钟检查一次
  private readonly MAX_QUERY_BROWSER_LIFETIME = 120000 // 临时Browser最大存活2分钟

  constructor() {
    super()
    this.buildLaunchConfig()
    this.startMonitoring()
  }

  /**
   * 构建启动配置（复用）
   */
  private buildLaunchConfig() {
    const launchArgs = [
      '--no-sandbox',
      '--disable-setuid-sandbox',
      '--disable-dev-shm-usage',
      '--disable-accelerated-2d-canvas',
      '--no-first-run',
      '--no-zygote',
      '--disable-gpu',
      '--disable-blink-features=AutomationControlled', // 反爬关键
    ]

    // 读取代理配置
    const proxyServer = process.env.PUPPETEER_PROXY || process.env.HTTP_PROXY || process.env.http_proxy
    if (proxyServer) {
      let proxyUrl = proxyServer
      if (!/^https?:\/\//.test(proxyUrl)) {
        proxyUrl = `http://${proxyUrl}`
      }
      launchArgs.push(`--proxy-server=${proxyUrl}`)

      // 🔑 关键：排除 localhost 和 127.0.0.1 从代理
      // 这样访问本地 proxy-server (3001端口) 不会经过代理
      launchArgs.push('--proxy-bypass-list=localhost,127.0.0.1')

      console.log(`🌐 使用代理: ${proxyUrl} (排除 localhost)`)
    }

    this.launchConfig = {
      headless: true,
      args: launchArgs
    }
  }

  /**
   * 初始化主Browser（用于弹幕连接）
   */
  async initialize(): Promise<void> {
    if (this.streamingInitPromise) {
      return this.streamingInitPromise
    }

    this.streamingInitPromise = this._doInitializeStreaming()
    return this.streamingInitPromise
  }

  private async _doInitializeStreaming(): Promise<void> {
    try {
      console.log('🚀 [主Browser] 启动中...')

      this.streamingBrowser = await puppeteer.launch(this.launchConfig)
      this.streamingPage = await this.streamingBrowser.newPage()

      // 反爬优化
      await this.streamingPage.evaluateOnNewDocument(() => {
        Object.defineProperty(navigator, 'webdriver', { get: () => false })
      })

      // 加载web页面
      console.log('📄 [主Browser] 加载web页面...')
      await this.streamingPage.goto(`http://localhost:${PORT}`, {
        waitUntil: 'networkidle0',
        timeout: 30000
      })

      // 设置页面通信
      await this.setupStreamingCommunication()

      this.isStreamingInitialized = true
      console.log('✅ [主Browser] 初始化完成')
    } catch (error) {
      console.error('❌ [主Browser] 初始化失败:', error)
      await this.cleanupStreaming()
      throw error
    }
  }

  /**
   * 设置主Browser的页面通信
   */
  private async setupStreamingCommunication(): Promise<void> {
    if (!this.streamingPage) return

    // 暴露数据接收函数
    await this.streamingPage.exposeFunction('__puppeteerReceive', (data: PageEvent) => {
      this.handlePageEvent(data)
    })

    // 暴露日志函数
    await this.streamingPage.exposeFunction('__puppeteerLog', (level: string, ...args: any[]) => {
      console.log(`[主Browser ${level}]:`, ...args)
    })
  }

  /**
   * 处理页面事件
   */
  private handlePageEvent(data: PageEvent): void {
    switch (data.type) {
      case 'connection_opened':
        this.emit('roomConnected', data)
        break
      case 'messages':
        this.emit('newMessages', data )
        break
      case 'connection_closed':
        this.emit('roomDisconnected', data)
        break
      case 'connection_error':
        this.emit('connectionError', data)
        break
      case 'reconnecting':
        this.emit('reconnecting', data)
        break
      case 'connection_failed':
        this.emit('connectionFailed', data)
        break
      case 'live_info_success':
        this.emit('liveInfoSuccess', data)
        break
      case 'live_info_failed':
        this.emit('liveInfoFailed', data)
        break
      default:
        console.log('未知页面事件:', data)
    }
  }

  /**
   * 获取或创建查询Browser（复用模式）
   * 每个Browser可以使用10次，达到上限后销毁并创建新的
   */
  private async getOrCreateQueryBrowser(): Promise<{ browser: Browser; page: Page; isNew: boolean }> {
    // 检查是否需要创建新Browser
    const needNewBrowser =
      !this.currentQueryBrowser ||
      !this.currentQueryPage ||
      this.queryBrowserUseCount >= this.MAX_QUERY_USE_COUNT;

    if (needNewBrowser) {
      // 清理旧Browser
      if (this.currentQueryBrowser) {
        console.log(`🔄 [Browser复用] 达到最大使用次数 (${this.queryBrowserUseCount}/${this.MAX_QUERY_USE_COUNT})，创建新Browser`)
        try {
          if (this.currentQueryPage) await this.currentQueryPage.close()
          this.activeQueryBrowsers.delete(this.currentQueryBrowser)
          this.queryBrowserTimestamps.delete(this.currentQueryBrowser)
          await this.currentQueryBrowser.close()
        } catch (error) {
          console.error('清理旧查询Browser时出错:', error)
        }
      }

      // 创建新Browser
      console.log(`🚀 [Browser复用] 创建新查询Browser`)
      this.currentQueryBrowser = await puppeteer.launch(this.launchConfig)
      this.activeQueryBrowsers.add(this.currentQueryBrowser)
      this.queryBrowserTimestamps.set(this.currentQueryBrowser, Date.now())

      this.currentQueryPage = await this.currentQueryBrowser.newPage()

      // 反爬优化
      await this.currentQueryPage.evaluateOnNewDocument(() => {
        Object.defineProperty(navigator, 'webdriver', { get: () => false })
      })

      // 随机延迟 1-3 秒（模拟人类行为）
      const delay = Math.random() * 2000 + 1000
      await new Promise(resolve => setTimeout(resolve, delay))

      // 加载页面
      await this.currentQueryPage.goto(`http://localhost:${PORT}`, {
        waitUntil: 'networkidle0',
        timeout: 30000
      })

      // 暴露日志函数
      await this.currentQueryPage.exposeFunction('__puppeteerLog', (level: string, ...args: any[]) => {
        console.log(`[Browser复用 ${level}]:`, ...args)
      })

      // 重置计数器
      this.queryBrowserUseCount = 0

      return { browser: this.currentQueryBrowser, page: this.currentQueryPage, isNew: true }
    } else {
      // 复用现有Browser
      return { browser: this.currentQueryBrowser!, page: this.currentQueryPage!, isNew: false }
    }
  }

  /**
   * 获取直播间信息（Browser复用模式）
   * 每个Browser可以使用10次，达到上限后自动创建新Browser
   * @param input 可以是房间号（纯数字）、主播主页URL、sec_uid或抖音号
   */
  async getLiveInfo(input: string): Promise<DyLiveInfo> {
    try {
      // 获取或创建查询Browser
      const { browser, page, isNew } = await this.getOrCreateQueryBrowser()

      // 递增使用计数
      this.queryBrowserUseCount++

      console.log(
        `🔍 [Browser复用] 查询: ${input} (${isNew ? '新建' : '复用'} Browser, 使用次数: ${this.queryBrowserUseCount}/${this.MAX_QUERY_USE_COUNT})`
      )

      // 执行查询
      const result: DyLiveInfo = await page.evaluate(async (input: string) => {
        return await window.getLiveInfo(input)
      }, input)

      console.log(`✅ [Browser复用] 查询成功: ${input}`)
      return result

    } catch (error) {
      console.error(`❌ [Browser复用] 查询失败 (${input}):`, error)

      // 查询失败时，强制重置Browser（可能是Browser状态异常）
      if (this.currentQueryBrowser) {
        console.log(`⚠️  [Browser复用] 查询失败，重置Browser`)
        try {
          if (this.currentQueryPage) await this.currentQueryPage.close()
          this.activeQueryBrowsers.delete(this.currentQueryBrowser)
          this.queryBrowserTimestamps.delete(this.currentQueryBrowser)
          await this.currentQueryBrowser.close()
        } catch (cleanupError) {
          console.error('重置Browser时出错:', cleanupError)
        }
        this.currentQueryBrowser = null
        this.currentQueryPage = null
        this.queryBrowserUseCount = 0
      }

      throw error
    }
  }

  /**
   * 连接直播间（使用主Browser）
   */
  async connectLiveRoom(roomId: string): Promise<{ success: boolean; message: string }> {
    await this.ensureStreamingInitialized()

    try {
      const result: { success: boolean; message: string } = await this.streamingPage!.evaluate((roomId: string) => {
        return window.connectLiveRoom(roomId)
      }, roomId)

      console.log(`🔗 [主Browser] 已连接直播间: ${roomId}`)
      return result
    } catch (error) {
      console.error(`❌ [主Browser] 连接直播间 ${roomId} 失败:`, error)
      throw error
    }
  }

  /**
   * 确保主Browser已初始化
   */
  private async ensureStreamingInitialized(): Promise<void> {
    if (!this.isStreamingInitialized) {
      await this.initialize()
    }
  }

  /**
   * 清理主Browser资源
   */
  private async cleanupStreaming(): Promise<void> {
    try {
      if (this.streamingPage) {
        await this.streamingPage.close()
        this.streamingPage = null
      }
      if (this.streamingBrowser) {
        await this.streamingBrowser.close()
        this.streamingBrowser = null
      }
      this.isStreamingInitialized = false
      this.streamingInitPromise = null
      console.log('🧹 [主Browser] 资源已清理')
    } catch (error) {
      console.error('清理主Browser资源时出错:', error)
    }
  }

  /**
   * 清理所有资源（包括主Browser和所有临时Browser）
   */
  async cleanup(): Promise<void> {
    // 停止监控
    this.stopMonitoring()

    // 清理当前查询Browser
    if (this.currentQueryBrowser) {
      console.log(`🧹 清理当前查询Browser (使用次数: ${this.queryBrowserUseCount})`)
      try {
        if (this.currentQueryPage) await this.currentQueryPage.close()
        await this.currentQueryBrowser.close()
      } catch (error) {
        console.error('清理当前查询Browser时出错:', error)
      }
      this.currentQueryBrowser = null
      this.currentQueryPage = null
      this.queryBrowserUseCount = 0
    }

    // 清理所有活跃的临时Browser（遗留的）
    console.log(`🧹 清理 ${this.activeQueryBrowsers.size} 个临时Browser...`)
    for (const browser of this.activeQueryBrowsers) {
      try {
        await browser.close()
      } catch (error) {
        console.error('关闭临时Browser时出错:', error)
      }
    }
    this.activeQueryBrowsers.clear()
    this.queryBrowserTimestamps.clear()

    // 清理主Browser
    await this.cleanupStreaming()

    console.log('🧹 所有Puppeteer资源已清理')
  }

  /**
   * 重启主Browser实例
   */
  async restart(): Promise<void> {
    console.log('🔄 重启主Browser实例...')
    await this.cleanupStreaming()
    await this.initialize()
  }

  /**
   * 检查主Browser状态
   */
  isReady(): boolean {
    return this.isStreamingInitialized && this.streamingBrowser !== null && this.streamingPage !== null
  }

  /**
   * 获取活跃的临时Browser数量（用于监控）
   */
  getActiveQueryBrowserCount(): number {
    return this.activeQueryBrowsers.size
  }

  /**
   * 启动Browser监控
   * 定期检查并清理超时的临时Browser
   */
  private startMonitoring() {
    this.monitorTimer = setInterval(() => {
      this.checkAndCleanupZombieBrowsers()
    }, this.MONITOR_INTERVAL)
  }

  /**
   * 检查并清理僵尸Browser
   * 如果临时Browser运行时间超过最大生命周期，强制关闭
   */
  private async checkAndCleanupZombieBrowsers() {
    const now = Date.now()
    const zombies: Browser[] = []

    for (const [browser, timestamp] of this.queryBrowserTimestamps.entries()) {
      const lifetime = now - timestamp
      if (lifetime > this.MAX_QUERY_BROWSER_LIFETIME) {
        console.warn(`⚠️  发现僵尸Browser (存活 ${Math.round(lifetime / 1000)}秒)，强制清理`)
        zombies.push(browser)
      }
    }

    // 清理僵尸Browser
    for (const browser of zombies) {
      try {
        await browser.close()
        this.activeQueryBrowsers.delete(browser)
        this.queryBrowserTimestamps.delete(browser)
        console.log(`🧹 已清理僵尸Browser`)
      } catch (error) {
        console.error('清理僵尸Browser失败:', error)
      }
    }

    // 定期输出统计信息
    if (this.activeQueryBrowsers.size > 0) {
      console.log(`📊 Browser统计: 主Browser=${this.isStreamingInitialized ? '运行中' : '未启动'}, 临时Browser=${this.activeQueryBrowsers.size}个`)
    }
  }

  /**
   * 停止监控
   */
  private stopMonitoring() {
    if (this.monitorTimer) {
      clearInterval(this.monitorTimer)
      this.monitorTimer = null
    }
  }
}

export const puppeteerManager = new PuppeteerManager()
puppeteerManager.initialize();





